#!/usr/bin/env python3
"""Common machinery for tests."""

#
# Copyright 2024  Odin Kroeger
#
# This file is part of SieveManager.
#
# SieveManager is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# SieveManager is distributed in the hope that it will be useful,
# but WITHOUT ALL WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SieveManager. If not, see <https://www.gnu.org/licenses/>.
#

#
# Modules
#

from typing import TypeVar, Union, Iterable, Callable

import unittest


#
# Types
#

T = TypeVar('T')
"""Type variable."""

Test = tuple[Iterable, Union[T, type[Exception]]]
"""Test to be run with :func:`runtests`."""


#
# Functions
#

def runtests(unit: unittest.TestCase, func: Callable[..., T],
             tests: Iterable[Test[T]]):
    """Run `tests` for `func` in `unit`."""
    for i, (args, exp) in enumerate(tests):
        with unit.subTest(i=i, args=args, exp=exp):
            try:
                retval = func(*args)
            except Exception as exc:
                if isinstance(exp, type) and isinstance(exc, exp):
                    continue
                raise
            unit.assertEqual(retval, exp)


def makerunner(func: Callable[..., T], tests: Iterable[Test[T]]):
    """Get :class:`unittest.TestCase` method that runs `tests` for `func`."""
    return lambda unit: runtests(unit, func, tests)
